-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local test_bios_conf = {}
require 'ipmi'
local bs = require 'mc.bitstring'
local log = require 'mc.logging'
local BIOS_PATH = '/bmc/kepler/Systems/1/Bios'
local BIOS_INTERFACE = 'bmc.kepler.Systems.Bios'
local BIOS_OPTION_PATH = '/bmc/kepler/Systems/1/BootOptions'
local BIOS_OPTION_INTERFACE = 'bmc.kepler.Systems.BootOptions'
local test_bios_common = require 'test_bios_common'
local mdb = require 'mc.mdb'
local lu = require 'luaunit'

require 'bios.json_types.BootOptions'
require 'bios.json_types.Bios'

function test_bios_conf.test_set_mode_switch(bus)
    local obj = mdb.get_object(bus, BIOS_OPTION_PATH, BIOS_OPTION_INTERFACE)

    local resp = obj:ShieldIpmiModifyBootModeSupport_PACKED(require'mc.context'.new(), true)
    assert(resp.RespCode == 0)
    lu.assertEquals(obj.BootModeSupport, false)

    resp = obj:ShieldIpmiModifyBootModeSupport_PACKED(require'mc.context'.new(), false)
    assert(resp.RespCode == 0)
    lu.assertEquals(obj.BootModeSupport, true)
end

function test_bios_conf.test_clear_cmos(bus)
    local obj = mdb.get_object(bus, BIOS_PATH, BIOS_INTERFACE)
    local resp =
        obj:ClearCmos_PACKED(
            {Interface = 'om', UserName = 'N/A', ClientAddr = '127.0.0.1', Privilege = '16'}
        )
    assert(resp.Result == 0)
end

function test_bios_conf.test_reset_bios(bus)
    local obj = mdb.get_object(bus, BIOS_PATH, BIOS_INTERFACE)
    local resp =
        obj:ResetSetupConfig_PACKED(
            {Interface = 'om', UserName = 'N/A', ClientAddr = '127.0.0.1', Privilege = '16'}
        )
    assert(resp.Result == 0)
end

function test_bios_conf.test_reset_pwd(bus)
    local obj = mdb.get_object(bus, BIOS_PATH, BIOS_INTERFACE)
    local ok = pcall(function()
        obj:ChangePassword_PACKED(require'mc.context'.new(),
        "Admin", "aaa", "Admin@90000")
    end)
    assert(ok == false)

    ok = pcall(function()
        obj:ChangePassword_PACKED(require'mc.context'.new(),
        "Supervisor", "aaa", "Admin@90000")
    end)
    assert(ok == true)
end

local function send_ipmi(data)
    return test_bios_common.send_ipmi(data)
end

local PASSWORD_RSP = '<<ManufactureId:3/unit:8, Information/string>>'

function test_bios_conf.test_ipmi_ack_pwd(bus)
    -- ipmi获取管理员密码
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x47 0x00 0x00 0x00')
    if ok then
        local data = bs.new(PASSWORD_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
    end

    -- ipmi确认管理员密码:没有information
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x47 0x00 0x01 0x00')
    lu.assertEquals(ok, false)

     -- ipmi确认管理员密码
     ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x47 0x00 0x01 0x00 0x00')
     lu.assertEquals(ok, true)

    -- rpc设置普通用户密码
    local obj = mdb.get_object(bus, BIOS_PATH, BIOS_INTERFACE)
    local resp = obj:ChangePassword_PACKED(require'mc.context'.new(),
        "UserPassword", "aaa", "Admin@90000")
    assert(resp.Result == 0)

    -- ipmi获取普通用户密码
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x47 0x00 0x00 0x01')
    lu.assertEquals(ok, true)

    -- ipmi确认普通用户密码
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x47 0x00 0x01 0x01 0x00')
    lu.assertEquals(ok, true)
end

function test_bios_conf.test_ipmi_cmos()
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x03 0x06')
    lu.assertEquals(ok, true)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x03 0x00')
    lu.assertEquals(ok, true)
end

function test_bios_conf.test_get_bios_boot_info()
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x01 0x00')
    lu.assertEquals(ok, false)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x00 0x00')
    lu.assertEquals(ok, false)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x00 0x03')
    lu.assertEquals(ok, true)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x00 0x04')
    lu.assertEquals(ok, true)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x00 0x05')
    lu.assertEquals(ok, true)

    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5C 0x00 0x06')
    lu.assertEquals(ok, true)
end

function test_bios_conf.test_set_bios_boot_info()
    -- 长度不合法
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x00 0x05 0x00')
    lu.assertEquals(ok, false)

    -- biosId不合法
    send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x01 0x00 0x05 0x00')
    lu.assertEquals(ok, false)

    -- 属性不合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x00 0x01 0x00')
    lu.assertEquals(ok, false)

    -- BiosPrintFlag属性长度不合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x03 0x02 0x00 0x00')
    lu.assertEquals(ok, false)

    -- BiosPrintFlag属性取值合法,导入文件失败
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x03 0x01 0x00')
    lu.assertEquals(ok, false)

    -- BootModeSupport属性长度不合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x04 0x02 0x00 0x00')
    lu.assertEquals(ok, false)

    -- BootModeSupport属性取值合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x04 0x01 0x00')
    lu.assertEquals(ok, true)

    -- BootSourceOverrideMode属性长度不合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x05 0x02 0x00 0x00')
    lu.assertEquals(ok, false)

    -- BootSourceOverrideMode取值不合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x05 0x01 0x02')
    lu.assertEquals(ok, false)

    -- BootSourceOverrideMode取值合法
    ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5D 0x00 0x05 0x01 0x01')
    lu.assertEquals(ok, true)
end

function test_bios_conf.test_conf(bus)
    log:info('================ test bios conf start ================')
    test_bios_conf.test_set_mode_switch(bus)
    test_bios_conf.test_clear_cmos(bus)
    test_bios_conf.test_reset_bios(bus)
    test_bios_conf.test_reset_pwd(bus)
    test_bios_conf.test_ipmi_ack_pwd(bus)

    test_bios_conf.test_ipmi_cmos()
    test_bios_conf.test_get_bios_boot_info()
    test_bios_conf.test_set_bios_boot_info()
    log:info('================ test bios conf end ================')
end

return test_bios_conf
